package com.atguigu.tingshu.album.service.impl;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;

import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Maps;

import com.atguigu.tingshu.album.config.VodConstantProperties;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.util.UploadFileUtil;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qcloud.vod.VodUploadClient;
import com.qcloud.vod.model.VodUploadRequest;
import com.qcloud.vod.model.VodUploadResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

	@Autowired
	private TrackInfoMapper trackInfoMapper;

	@Autowired
	private TrackStatMapper trackStatMapper ;

	@Autowired
	private VodService vodService ;

	@Autowired
	private AlbumInfoMapper albumInfoMapper ;

	@Autowired
	private UserInfoFeignClient userInfoFeignClient ;

	@Autowired
	private AlbumStatMapper albumStatMapper;

	@Override
	public UploadTrackVo uploadTrack(MultipartFile file) {
		return vodService.uploadTrack(file) ;
	}

	@Transactional
	@Override
	public void saveTrackInfo(TrackInfoVo trackInfoVo) {

		// 获取当前登录用户的id
		Long userId = AuthContextHolder.getUserId();

		// 1.保存声音基本信息(track_info)
		TrackInfo trackInfo = new TrackInfo();			// 创建TrackInfo对象，封装要保存的数据
		BeanUtils.copyProperties(trackInfoVo , trackInfo);
		trackInfo.setSource(SystemConstant.TRACK_SOURCE_UPLOAD);
		trackInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);
		trackInfo.setUserId(userId);

		/**
		 * 先根据专辑的id从声音的基本信息表中获取声音的列表数据(需要根据order_num进行倒序排序)
		 * 判断列表数据是否为空：
		 * 1、如果为空，orderNum = 1
		 * 2、如果不为空，从声音列表集合中获取第一个声音基本信息对象，获取到orderNum的值，对orderNum进行+1操作
		 */
		LambdaQueryWrapper<TrackInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>() ;
		lambdaQueryWrapper.eq(TrackInfo::getAlbumId , trackInfoVo.getAlbumId()) ;
		lambdaQueryWrapper.orderByDesc(TrackInfo::getOrderNum) ;
		lambdaQueryWrapper.last("limit 1") ;

		// sql语句：select * from track_info where album_id = ? order by order_num desc limit 1
		TrackInfo dbTrackInfo = trackInfoMapper.selectOne(lambdaQueryWrapper);
		if(dbTrackInfo == null) {
			trackInfo.setOrderNum(1);
		}else {
			Integer orderNum = dbTrackInfo.getOrderNum();
			orderNum++ ;
			trackInfo.setOrderNum(orderNum);
		}

		// 调用腾讯云点播服务的接口获取媒体相关数据
		TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId()) ;
		trackInfo.setMediaDuration(new BigDecimal(trackMediaInfoVo.getDuration()));
		trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
		trackInfo.setMediaSize(trackMediaInfoVo.getSize());
		trackInfo.setMediaType(trackMediaInfoVo.getType());
		trackInfoMapper.insert(trackInfo) ;

		// 2、初始化声音统计数据
		this.saveTrackStat(trackInfo.getId() , SystemConstant.TRACK_STAT_PLAY);
		this.saveTrackStat(trackInfo.getId() , SystemConstant.TRACK_STAT_COLLECT);
		this.saveTrackStat(trackInfo.getId() , SystemConstant.TRACK_STAT_PRAISE);
		this.saveTrackStat(trackInfo.getId() , SystemConstant.TRACK_STAT_COMMENT);

		// 3、修改专辑基本信息表中的include_track_count字段值
		AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
		Integer includeTrackCount = albumInfo.getIncludeTrackCount();
		includeTrackCount++ ;
		albumInfo.setIncludeTrackCount(includeTrackCount);
		albumInfoMapper.updateById(albumInfo) ;

	}

	@Override
	public IPage<TrackListVo> findUserTrackPage(Integer pageNo, Integer pageSize, TrackInfoQuery trackInfoQuery) {

		// 进行条件分页查询
		Long userId = AuthContextHolder.getUserId();
		trackInfoQuery.setUserId(userId);

		// 创建Page对象，封装分页参数
		Page<TrackListVo> page = new Page<>(pageNo , pageSize) ;
		IPage<TrackListVo> trackListVoIPage =  trackInfoMapper.findUserTrackPage(page , trackInfoQuery)  ;

		// 返回
		return trackListVoIPage;
	}

	@Override
	public void updateTrackInfo(Long id, TrackInfoVo trackInfoVo) {

		// 1、根据id查询声音基本信息
		TrackInfo trackInfo = trackInfoMapper.selectById(id);

		/**
		 * 判断用户是否重新上传了声音，如果是就需要根据新的媒体文件的id查询媒体信息，然后修改媒体信息
		 */
		String dbMediaFileId = trackInfo.getMediaFileId();
		String mediaFileId = trackInfoVo.getMediaFileId();
		if(!dbMediaFileId.equals(mediaFileId)) {

			// 调用腾讯云点播服务的接口获取媒体相关数据
			TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(mediaFileId);
			trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
			trackInfo.setMediaSize(trackMediaInfoVo.getSize());
			trackInfo.setMediaDuration(new BigDecimal(trackMediaInfoVo.getDuration()));
			trackInfo.setMediaType(trackMediaInfoVo.getType());

			// TODO: 调用腾讯云点播服务的接口删除媒体文件信息

		}

		BeanUtils.copyProperties(trackInfoVo , trackInfo);
		trackInfoMapper.updateById(trackInfo) ;

	}

	@Transactional
	@Override
	public void removeTrackInfo(Long id) {

		// 根据声音的id查询声音数据
		TrackInfo trackInfo = trackInfoMapper.selectById(id);

		// 1、根据声音的id删除声音基本数据
		trackInfoMapper.deleteById(id) ;

		// 2、根据声音的id删除声音统计数据
		LambdaQueryWrapper<TrackStat> lambdaQueryWrapper = new LambdaQueryWrapper<>() ;
		lambdaQueryWrapper.eq(TrackStat::getTrackId , id) ;
		trackStatMapper.delete(lambdaQueryWrapper) ;

		// 3、修改专辑基本信息表中的include_track_count字段值
		Long albumId = trackInfo.getAlbumId();
		AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
		Integer includeTrackCount = albumInfo.getIncludeTrackCount();
		includeTrackCount-- ;
		albumInfo.setIncludeTrackCount(includeTrackCount);
		albumInfoMapper.updateById(albumInfo) ;

		// 4、调用腾讯云点播服务的接口删除媒体文件信息
		vodService.removeMediaFile(trackInfo.getMediaFileId()) ;

	}

	@Override
	public IPage<AlbumTrackListVo> findAlbumTrackPage(Long albumId, Integer pageNo, Integer pageSize) {

		// 根据专辑的id查询专辑数据
		AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
		String payType = albumInfo.getPayType();

		// 分页查询专辑的声音列表
		IPage<AlbumTrackListVo> page = new Page<>(pageNo , pageSize) ;
		trackInfoMapper.findAlbumTrackPage(page , albumId) ;

		List<AlbumTrackListVo> records = page.getRecords();		// 获取当前页的声音列表数据
		Long userId = AuthContextHolder.getUserId();			// 获取当前登录用户的id

		if(userId == null) {									// 用户未登录

			// 判断专辑的付费类型
			if(!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(payType)) {
				Integer tracksForFree = albumInfo.getTracksForFree();		// 获取试听的声音数
				records.stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > tracksForFree)
						.forEach(albumTrackListVo -> albumTrackListVo.setIsShowPaidMark(true));
			}

		}else {			// 用户已经登录了

			// 判断声音付费类型是否为vip免费
			if(SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(payType)) {		// vip免费

				// 判断当前登录用户的身份
				Result<UserInfo> userInfoResult = userInfoFeignClient.getUserInfoById(userId);
				UserInfo userInfo = userInfoResult.getData();
				if(userInfo.getIsVip().intValue() == 1) {     // 是vip用户

					// 判断vip是否过期
					Date vipExpireTime = userInfo.getVipExpireTime();
					if(vipExpireTime.before(new Date())) {   // vip过期了
						Integer tracksForFree = albumInfo.getTracksForFree();		// 获取试听的声音数
						records.stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > tracksForFree)
								.forEach(albumTrackListVo -> albumTrackListVo.setIsShowPaidMark(true));
					}


				}else {		//  非vip用户
					Integer tracksForFree = albumInfo.getTracksForFree();		// 获取试听的声音数
					records.stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > tracksForFree)
							.forEach(albumTrackListVo -> albumTrackListVo.setIsShowPaidMark(true));
				}

			}else  if(SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {		// 付费专辑

				/**
				 * 根据用户的购买情况，构建isShowPaidMark：
				 * 1、如果用户购买过该专辑，把非试听声音isShowPaidMark的值设置为false
				 * 2、如果用户未购买过该专辑，但是购买过某一个声音，那么就应该把这个声音isShowPaidMark的值设置为false
				 *
				 * 用户购买的声音或者专辑信息是在哪一张表中记录了？
				 * 1、user_paid_album记录了专辑的购买信息
				 * 2、user_paid_track记录了声音的购买信息
				 */
				Integer tracksForFree = albumInfo.getTracksForFree();		// 获取试听的声音数
				List<Long> noFreeTrackIds = records.stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > tracksForFree)
						.map(albumTrackListVo -> albumTrackListVo.getTrackId()).collect(Collectors.toList());

				// 远程调用user微服务的接口，判断noFreeTrackIds中的声音是否购买过
				//  Map键表示是的就是声音的id ， Map的值表示是否购买过： 0表示未购买过   1表示购买过
				Result<Map<Long , Integer>> isPaidTrackResult =  userInfoFeignClient.userIsPaidTrack(albumId , noFreeTrackIds);   // 8 ， 9 ， 10 ， 11
				Map<Long, Integer> trackResulData = isPaidTrackResult.getData();
				records.stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > tracksForFree)
						.forEach(albumTrackListVo -> {
							Long trackId = albumTrackListVo.getTrackId();
							int isPaid = trackResulData.get(trackId);
							boolean isShowPaidMark =  !(isPaid == 1) ;
							albumTrackListVo.setIsShowPaidMark(isShowPaidMark);
						});

			}

		}

		return page;
	}

	@Transactional
	@Override
	public void updateTrackStat(TrackStatMqVo trackStatMqVo) {

		// 更新track_stat表中的数据值，和album_stat表中的数据值
		// 根据声音的id和stat_type进行数据的查询
		LambdaQueryWrapper<TrackStat> trackStatLambdaQueryWrapper = new LambdaQueryWrapper<>() ;
		trackStatLambdaQueryWrapper.eq(TrackStat::getTrackId , trackStatMqVo.getTrackId()) ;
		trackStatLambdaQueryWrapper.eq(TrackStat::getStatType , trackStatMqVo.getStatType()) ;
		TrackStat trackStat = trackStatMapper.selectOne(trackStatLambdaQueryWrapper);
		trackStat.setStatNum(trackStat.getStatNum() + trackStatMqVo.getCount());
		trackStatMapper.updateById(trackStat) ;

		// 更新album_stat表中的数据值
		LambdaQueryWrapper<AlbumStat> albumStatLambdaQueryWrapper = new LambdaQueryWrapper<>() ;
		albumStatLambdaQueryWrapper.eq(AlbumStat::getAlbumId , trackStatMqVo.getAlbumId()) ;
		switch (trackStatMqVo.getStatType()) {
			case SystemConstant.TRACK_STAT_PLAY:
				albumStatLambdaQueryWrapper.eq(AlbumStat::getStatType , SystemConstant.ALBUM_STAT_PLAY) ;
				break;
			case SystemConstant.TRACK_STAT_COLLECT:
				albumStatLambdaQueryWrapper.eq(AlbumStat::getStatType , SystemConstant.ALBUM_STAT_SUBSCRIBE) ;
				break;
			case SystemConstant.TRACK_STAT_PRAISE:
				albumStatLambdaQueryWrapper.eq(AlbumStat::getStatType , SystemConstant.ALBUM_STAT_BROWSE) ;
				break;
			case SystemConstant.TRACK_STAT_COMMENT:
				albumStatLambdaQueryWrapper.eq(AlbumStat::getStatType , SystemConstant.ALBUM_STAT_COMMENT) ;
				break;
		}
		AlbumStat albumStat = albumStatMapper.selectOne(albumStatLambdaQueryWrapper);
		albumStat.setStatNum(albumStat.getStatNum() + trackStatMqVo.getCount());
		albumStatMapper.updateById(albumStat) ;

	}

	@Override
	public TrackStatVo getTrackStatVo(Long trackId) {
		return trackStatMapper.getTrackStatVo(trackId);
	}

	@Override
	public List<TrackPayVo> findUserTrackPaidList(Long trackId) {

		// 根据声音的id查询声音信息
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
		Long albumId = trackInfo.getAlbumId();

		// 根据专辑的id查询专辑
		AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);

		// 1、先根据专辑Id获取到当前用户登录用户购买的声音Id集合
		Result<List<Long>> userPaidTrackListResult = userInfoFeignClient.findUserPaidTrackList(albumId);
		List<Long> userPaidTrackIds = userPaidTrackListResult.getData();

		// 2、获取到当前专辑{albumId}中大于当前声音的orderNum所对应的前声音Id的集合列表
		// select * from track_info where album_id = ? and order_num > ?
		LambdaQueryWrapper<TrackInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>() ;
		lambdaQueryWrapper.eq(TrackInfo::getAlbumId , albumId) ;
		lambdaQueryWrapper.gt(TrackInfo::getOrderNum , trackInfo.getOrderNum()) ;
		lambdaQueryWrapper.select(TrackInfo::getId) ;
		List<TrackInfo> trackInfoList = trackInfoMapper.selectList(lambdaQueryWrapper);
		List<Long> trackIds = trackInfoList.stream().map(track -> track.getId()).collect(Collectors.toList());

		// 3、计算需要分集的声音id集合
		List<Long> trackIdNoReaptList = new ArrayList<>() ;
		if(CollectionUtils.isEmpty(userPaidTrackIds)) {
			trackIdNoReaptList = trackIds ;
		}else {
			for(Long id : trackIds) {
				if(!userPaidTrackIds.contains(id)) {
					trackIdNoReaptList.add(id) ;
				}
			}
		}

		// 4、进行分集操作，构建响应结果数据并返回
		List<TrackPayVo> trackPayVoList = new ArrayList<>() ;

		// 构建本集
		TrackPayVo trackPayVo = new TrackPayVo() ;
		trackPayVo.setName("本集");
		trackPayVo.setPrice(albumInfo.getPrice());
		trackPayVo.setTrackCount(0);
		trackPayVoList.add(trackPayVo) ;

		// 构建剩余分集
		int size = trackIdNoReaptList.size();
		if(size > 0 && size <= 10) {
			TrackPayVo pay = new TrackPayVo() ;
			pay.setName("后" + size + "集");
			pay.setPrice(albumInfo.getPrice().multiply(new BigDecimal(size)));
			pay.setTrackCount(size);
			trackPayVoList.add(pay) ;
		}

		if(size > 10) {
			TrackPayVo pay = new TrackPayVo() ;
			pay.setName("后10集");
			pay.setPrice(albumInfo.getPrice().multiply(new BigDecimal(10)));
			pay.setTrackCount(10);
			trackPayVoList.add(pay) ;
		}

		// 判断
		if(size > 10 && size <= 20) {
			TrackPayVo pay = new TrackPayVo() ;
			pay.setName("后" + size + "集");
			pay.setPrice(albumInfo.getPrice().multiply(new BigDecimal(size)));
			pay.setTrackCount(size);
			trackPayVoList.add(pay) ;
		}

		if(size > 20) {
			TrackPayVo pay = new TrackPayVo() ;
			pay.setName("后20集");
			pay.setPrice(albumInfo.getPrice().multiply(new BigDecimal(20)));
			pay.setTrackCount(20);
			trackPayVoList.add(pay) ;
		}

		if(size > 20 && size <= 30) {
			TrackPayVo pay = new TrackPayVo() ;
			pay.setName("后" + size + "集");
			pay.setPrice(albumInfo.getPrice().multiply(new BigDecimal(size)));
			pay.setTrackCount(size);
			trackPayVoList.add(pay) ;
		}

		if(size > 30) {
			TrackPayVo pay = new TrackPayVo() ;
			pay.setName("后30集");
			pay.setPrice(albumInfo.getPrice().multiply(new BigDecimal(30)));
			pay.setTrackCount(30);
			trackPayVoList.add(pay) ;
		}

		if(size > 30 && size <= 50) {
			TrackPayVo pay = new TrackPayVo() ;
			pay.setName("后" + size + "集");
			pay.setPrice(albumInfo.getPrice().multiply(new BigDecimal(size)));
			pay.setTrackCount(size);
			trackPayVoList.add(pay) ;
		}

		if(size > 50) {
			TrackPayVo pay = new TrackPayVo() ;
			pay.setName("后50集");
			pay.setPrice(albumInfo.getPrice().multiply(new BigDecimal(50)));
			pay.setTrackCount(50);
			trackPayVoList.add(pay) ;
		}


		return trackPayVoList;
	}

	/**
	 * 根据声音的id，以及购买的数量查询声音列表数据
	 * @param tracKId
	 * @param trackCount
	 * @return
	 */
	@Override
	public List<TrackInfo> findPaidTrackInfoList(Long tracKId, Integer trackCount) {

		// 根据声音的id查询声音对象
		TrackInfo trackInfo = this.getById(tracKId);

		// 创建一个List集合对象，存储响应结果数据
		List<TrackInfo> trackInfoList = new ArrayList<>() ;

		// 判断trackCount的值，如果是0就说明要购买本集
		if(trackCount > 0) {

			// 查询用户购买的声音的id的集合
			Long albumId = trackInfo.getAlbumId();
			Result<List<Long>> userPaidTrackListResult = userInfoFeignClient.findUserPaidTrackList(albumId);
			List<Long> userPaidTrackIdList = userPaidTrackListResult.getData();

			// select * from track_info where album_id = ? and order_num > ? and id not in(? , ? , ?) limit ?
			LambdaQueryWrapper<TrackInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>() ;
			lambdaQueryWrapper.eq(TrackInfo::getAlbumId , albumId) ;
			lambdaQueryWrapper.gt(TrackInfo::getOrderNum , trackInfo.getOrderNum()) ;
			lambdaQueryWrapper.orderByAsc(TrackInfo::getOrderNum) ;
			if(!CollectionUtils.isEmpty(userPaidTrackIdList)) {
				lambdaQueryWrapper.notIn(TrackInfo::getId , userPaidTrackIdList) ;
			}
			lambdaQueryWrapper.last("limit " + trackCount) ;
			trackInfoList = trackInfoMapper.selectList(lambdaQueryWrapper);

		}else {		// 要购买本集
			trackInfoList.add(trackInfo) ;
		}

		// 返回
		return trackInfoList;
	}

	private void saveTrackStat(Long tracKId , String statType) {
		TrackStat trackStat = new TrackStat() ;
		trackStat.setTrackId(tracKId);
		trackStat.setStatType(statType);
		trackStat.setStatNum(0);
		trackStatMapper.insert(trackStat) ;
	}

}

